function fn() {
  for (var i = 0; i < 5; i++) {
    setTimeout(function () {
      console.log(i);
    }, 0);
  }
}

// 这个方法输出什么，为什么，怎么改写让他按顺序输出

这个函数会输出5个5，因为在 setTimeout 内部的回调函数是异步执行的，当 setTimeout 的回调函数被调用时，for 循环已经执行完毕，此时 i 的值已经是5了。

要让它按顺序输出0到4，可以使用 let 关键字声明循环变量 i，
因为 let 声明的变量具有块级作用域，每次迭代会创建一个新的变量，
而不是像 var 那样会造成变量提升的问题。

function fn() {
  for (let i = 0; i < 5; i++) {
    setTimeout(function () {
      console.log(i);
    }, 0);
  }
}

// 除了使用 let 关键字声明循环变量之外，
// 还可以通过闭包来解决这个问题。
// 在循环内部创建一个立即执行函数，并将循环变量作为参数传递给该函数，
// 这样就能够在每次迭代中创建一个新的闭包环境，
// 保存当前迭代的值。
function fn() {
  for (var i = 0; i < 5; i++) {
    (function (index) {
      setTimeout(function () {
        console.log(index);
      }, 0);
    })(i);
  }
}
